//
// +build !mipsle

package log

import (
	"fmt"
	"io"
	"os"
	"runtime"
	"strings"
	"sync"
	"time"
)

const (
	LevelTrace = iota
	LevelDebug
	LevelInfo
	LevelWarn
	LevelError
	LevelFatal
)

type Logger struct {
	level int
	mu    sync.Mutex
	out   io.Writer
}

func (l *Logger) Output(calldepth int, s string) error {
	now := time.Now().Format("01/02 15:04:05.99")
	l.mu.Lock()
	defer l.mu.Unlock()

	_, file, line, ok := runtime.Caller(calldepth)
	if !ok {
		file = "???"
		line = 0
	} else {
		file = strings.TrimPrefix(file, os.Getenv("GOPATH")+"/src/adai.design/jarvis/")
	}
	log := fmt.Sprintf("\033[90m"+"%s %s:%d "+"\033[0m"+"%s", now, file, line, s)
	l.out.Write([]byte(log))
	return nil
}

var std = &Logger{level: LevelTrace, out: os.Stderr}

func Printf(format string, v ...interface{}) {
	std.Output(2, fmt.Sprintf(format, v...))
}

func Println(v ...interface{}) {
	std.Output(2, fmt.Sprintln(v...))
}

func Trace(format string, v ...interface{}) {
	if std.level <= LevelTrace {
		std.Output(2, fmt.Sprintf("\033[90m"+format+"\033[0m\n", v...))
	}
}

func Debug(format string, v ...interface{}) {
	if std.level <= LevelDebug {
		std.Output(2, fmt.Sprintf(format+"\n", v...))
	}
}

func Info(format string, v ...interface{}) {
	if std.level <= LevelInfo {
		std.Output(2, fmt.Sprintf("\033[32m"+format+"\033[0m\n", v...))
	}
}

func InfoFrom(format string, v ...interface{}) {
	if std.level <= LevelInfo {
		std.Output(2, fmt.Sprintf("\033[32m"+format+"\033[0m\n", v...))
	}
}

func InfoTo(format string, v ...interface{}) {
	if std.level <= LevelInfo {
		std.Output(2, fmt.Sprintf("\033[34m"+format+"\033[0m\n", v...))
	}
}

func InfoR(format string, v ...interface{}) {
	if std.level <= LevelInfo {
		std.Output(2, fmt.Sprintf("\033[32m"+format+"\033[0m\n", v...))
	}
}

func InfoW(format string, v ...interface{}) {
	if std.level <= LevelInfo {
		std.Output(2, fmt.Sprintf("\033[34m"+format+"\033[0m\n", v...))
	}
}

func Warn(format string, v ...interface{}) {
	if std.level <= LevelWarn {
		std.Output(2, fmt.Sprintf("\033[33m"+format+"\033[0m\n", v...))
	}
}

func Error(format string, v ...interface{}) {
	if std.level <= LevelError {
		std.Output(2, fmt.Sprintf("\033[1;0;101m"+format+"\033[0m\n", v...))
	}
}

func Fatal(format string, v ...interface{}) {
	if std.level <= LevelFatal {
		s := fmt.Sprintf("\033[1;0;101m"+format+"\033[0m\n", v...)
		std.Output(2, s)
		panic(s)
	}
}
